package cn.exrick.xboot.modules.transport.baoxian.service;

import cn.exrick.xboot.common.exception.XbootException;
import cn.exrick.xboot.modules.transport.baoxian.config.InsuranceConfig;
import cn.exrick.xboot.modules.transport.baoxian.config.InsuranceStatus;
import cn.exrick.xboot.modules.transport.baoxian.config.XmlParser;
import cn.exrick.xboot.modules.transport.baoxian.dto.*;
import cn.exrick.xboot.modules.transport.entity.OrderCarInfo;
import cn.exrick.xboot.modules.transport.mapper.OrderCarInfoMapper;
import cn.hutool.core.util.CharsetUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.core.util.XmlUtil;
import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpResponse;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.Validate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.xml.bind.JAXBException;
import java.math.BigDecimal;
import java.time.LocalDateTime;

@Slf4j
@Service
@RequiredArgsConstructor
public class InsuranceService {

    private final InsuranceConfig config;
    private final OrderCarInfoMapper orderCarInfoMapper;

    // -------------------- 1. 获取MD5签名 --------------------
    public String getMd5Signature(String rawData) throws JAXBException {
        try {
            Md5SignRequest request = new Md5SignRequest();
            request.setRawData(rawData);
            request.setSecretKey(config.getSecretKey()); // 从配置读取密钥
            String requestXml = XmlParser.toRequestXml(request);
            log.info("InsuranceService getMd5Signature request :{}", requestXml);
            HttpResponse response = HttpRequest.post(config.getMd5Url()).charset(CharsetUtil.CHARSET_GBK)
                    .body(requestXml, "application/xml;charset=GBK")
                    .timeout(config.getTimeout())
                    .execute();
            log.info("InsuranceService getMd5Signature response :{}", response);
            return parseMd5Response(response.body());
        }catch (Exception e){
            log.error("InsuranceService getMd5Signature Exception ", e);
            throw new XbootException("保险请求加密异常");
        }

    }
    // -------------------- 工具方法 --------------------
    private String parseMd5Response(String xml) {
        return XmlUtil.readXML(xml).getDocumentElement()
                .getElementsByTagName("md5value").item(0).getTextContent();
    }

    // -------------------- 2. 提交投保 --------------------
    @Transactional(rollbackFor = Exception.class)
    public InsuranceApplyResponse submitApplication(InsuranceApplicationRequest request)  {
        try {
            request.setUsername(config.getUserName());
            String rawData = buildSignData(request);
            String md5Key = getMd5Signature(rawData);
            request.getPolicy().setMd5Key(md5Key);

            String requestXml = XmlParser.toRequestXml(request);
            log.info("InsuranceService submitApplication request :{}", requestXml);
            HttpResponse response = HttpRequest.post(config.getPolicyUrl()).charset(CharsetUtil.CHARSET_GBK)
                    .body(requestXml, "application/xml;charset=GBK")
                    .timeout(config.getTimeout())
                    .execute();
            log.info("InsuranceService submitApplication response :{}", response);
            //记录 保险下单
            return XmlParser.parseResponse(response.body(), InsuranceApplyResponse.class);
        } catch (Exception e) {
            log.error("InsuranceService submitApplication Exception ", e);
            throw new XbootException("保险下单异常");
        }
    }
    private String buildSignData(InsuranceApplicationRequest request) {
        return StrUtil.join("",
                request.getPolicy().getBusinessLogic(),
                request.getPolicy().getMainClauseCode(),
                request.getPolicy().getGoodsTypeNo(),
                request.getPolicy().getDepartureDate(),
                request.getPolicy().getEffDate(),
                request.getPolicy().getInsuredAmount().toString(),
                request.getPolicy().getRatio().toString()
        );
    }

    // -------------------- 3. 查询保单 --------------------
    public PolicyQueryResponse queryPolicy(String policyNo)  {
        try {
            PolicyQueryRequest request = new PolicyQueryRequest();
            request.setUsername(config.getUserName());
            request.getPolicy().setPolicyNo(policyNo);

            String rawData = buildQuerySignData(request);

            String md5Key = getMd5Signature(rawData);
            request.getPolicy().setMd5Key(md5Key);

            String requestXml = XmlParser.toRequestXml(request);
            log.info("InsuranceService queryPolicy request :{}", requestXml);
            HttpResponse response = HttpRequest.post(config.getPolicyUrl()).charset(CharsetUtil.CHARSET_GBK)
                    .body(requestXml, "application/xml;charset=GBK")
                    .timeout(config.getTimeout())
                    .execute();
            log.info("InsuranceService queryPolicy response :{}", response);
            return XmlParser.parseResponse(response.body(), PolicyQueryResponse.class);
        } catch (Exception e) {
            log.error("InsuranceService queryPolicy Exception ", e);
            throw new XbootException("保险单查询异常");
        }
    }

    private String buildQuerySignData(PolicyQueryRequest request) {
        return StrUtil.join("",
                request.getPolicy().getBusinessLogic(),
                request.getPolicy().getPolicyNo()
        );
    }



    public static void validate(InsuranceApplicationRequest request) {
        // 基础校验
        Validate.notBlank(request.getUsername(), "开户名不能为空");
        Validate.isTrue(request.getUsername().length() <= 20, "开户名长度不能超过20字符");

        InsuranceApplicationRequest.Policy policy = request.getPolicy();
        Validate.notNull(policy.getInsuredAmount(), "保险金额必填");
        Validate.isTrue(policy.getInsuredAmount().compareTo(BigDecimal.ZERO) > 0, "保险金额必须大于0");

        // 投保人条件校验
        if ("1".equals(policy.getHolderOverseas())) { // 境外客户
            Validate.notBlank(policy.getHolderCountryCode(), "境外客户国家代码必填");
        } else { // 境内客户
            Validate.notBlank(policy.getHolderProvince(), "省必填");
            Validate.notBlank(policy.getHolderCity(), "市必填");
            Validate.notBlank(policy.getHolderCountry(), "县必填");
        }
    }

    // -------------------- 4. 根据货物类型、主险条款等获取客户协议费率 --------------------
    public RateQueryResponse queryRate(RateQueryRequest request) throws JAXBException {
        try {
            request.setUsername(config.getUserName());

            String rawData = buildQueryRateSignData(request);
            String md5Key = getMd5Signature(rawData);
            if (StrUtil.isBlank(md5Key)) {
                return new RateQueryResponse();
            }
            request.getPolicy().setMd5Key(md5Key);

            String requestXml = XmlParser.toRequestXml(request);
            log.info("InsuranceService queryRate request :{}", requestXml);
            HttpResponse response = HttpRequest.post(config.getPolicyUrl()).charset(CharsetUtil.CHARSET_GBK)
                    .body(requestXml, "application/xml;charset=GBK")
                    .timeout(config.getTimeout())
                    .execute();
            log.info("InsuranceService queryRate response :{}", response);
            return XmlParser.parseResponse(response.body(), RateQueryResponse.class);
        } catch (Exception e) {
            log.error("InsuranceService queryRate Exception ", e);
            throw new XbootException("保险费率查询异常");
        }
    }
    private String buildQueryRateSignData(RateQueryRequest request) {
        return StrUtil.join("",
                request.getPolicy().getBusinessLogic(),
                request.getPolicy().getInsuranceId(),
                request.getPolicy().getGoodsTypeNo(),
                request.getPolicy().getIfPack(),
                request.getPolicy().getMainClauseCode()
        );
    }

    @Transactional(rollbackFor = Exception.class)
    public void updateSingleOrderStatus(OrderCarInfo orderCarInfo) {
        try {
            // 调用保险系统API获取最新状态
            PolicyQueryResponse policyQueryResponse = this.queryPolicy(orderCarInfo.getInsurancePolicyNo());

            // 状态未变化则跳过
            if (orderCarInfo.getInsuranceStatus().equals(InsuranceStatus.getDescByCode(Integer.valueOf(policyQueryResponse.getPolicy().getStatus())))) {
                return;
            }
            // 更新状态及时间戳
            orderCarInfo
                    .setInsuranceStatus(InsuranceStatus.getDescByCode(Integer.valueOf(policyQueryResponse.getPolicy().getStatus())))
                    .setInsuranceUpdateTime(LocalDateTime.now());
            orderCarInfoMapper.updateById(orderCarInfo);
        } catch (Exception e) {
            log.error("更新保单状态失败，保单号: {}，错误信息: {}", orderCarInfo.getInsurancePolicyNo(), e.getMessage());
        }
    }
}
